package com.tcl.aota.admin.util;

import com.tcl.aota.admin.dto.ApkDTO;
import com.tcl.aota.common.utils.StringUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.io.*;
import java.math.BigDecimal;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author kelong
 * @date 11/4/14
 */
public class ApkParser {

    private final static Logger LOG = Logger.getLogger(ApkParser.class);
    public static final String USES_PERMISSION = "uses-permission";
    public static final String PACKAGE = "package";
    public static final String APPLICATION_LABEL = "application-label:";
    public static final String APPLICATION = "application:";

    //    public String aaptPath = "/data/work/aapt/";

    private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";


    static {
        init();
    }

    public static void init() {
        String aaptPath = ApkParser.class.getResource("/").getPath();
        String command = "chmod 755 " + aaptPath + "aapt";
        try {
            Process process = Runtime.getRuntime().exec(
                new String[] {"/bin/sh", "-c", command});
        } catch (IOException e) {
            LOG.error("command error!" + e.getMessage(), e);
        }
    }

    /**
     * 解析apk字段
     *
     * @return
     */
    public ApkDTO apkParse(String apkPath, String iconOutPath) {
        if (StringUtils.isEmpty(apkPath)) {
            LOG.info("apkPath is empty.");
            return null;
        }
        String aaptPath = ApkParser.class.getResource("/").getPath();
        String command = aaptPath + "aapt d badging \"" + apkPath + "\"";
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(
                new String[] {"/bin/sh", "-c", command});
        } catch (IOException e) {
            process = null;
            LOG.error("command error!" + e.getMessage(), e);
        }
        if (process == null) {
            LOG.error("appt process is null!");
            return null;
        }
        InputStream is = null;
        BufferedReader br = null;
        ApkDTO apkDto = null;
        try {
            is = process.getInputStream();
            br = new BufferedReader(
                new InputStreamReader(is, "utf8"));
            String text = null;
            apkDto = new ApkDTO();
            while ((text = br.readLine()) != null) {
                parseColumn(apkDto, text);
            }
            //packageName,VersionName,VersionCode
            //packageName,VersionName,VersionCode
            apkDto.setFileSize(getSize(apkPath) + "");
            //抽取ICON
            if (!StringUtils.isEmpty(apkDto.getIconPath())) {
                apkDto.setIcon(parseIcon(apkPath, apkDto.getIconPath(), iconOutPath));
            }
            LOG.info("Apk Parse Success.packageName:" + apkDto.getPackageName() + ",versionCode:"
                + apkDto.getVersionCode());
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            try {
                if (is != null)
                    is.close();
                if (br != null)
                    br.close();
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
            }
        }
        return apkDto;
    }

    /**
     * 解析字段
     *
     * @param apkDTO
     * @param source
     */
    private void parseColumn(ApkDTO apkDTO, String source) {
        if (source.startsWith(PACKAGE)) {
            splitPackageInfo(apkDTO, source);
        } else if (source.startsWith(USES_PERMISSION)) {
            apkDTO.addPermissions(getPropertyInQuote(source));
        } else if (source.startsWith(APPLICATION_LABEL)) {
            apkDTO.setAppName(getPropertyInQuote(source));
        } else if (source.startsWith(APPLICATION)) {
            apkDTO.setIconPath(getIconPath(source));
        }
    }

    private String getPropertyInQuote(String source) {
        int start = source.indexOf("'") + 1;
        int end = source.indexOf('\'', start);
        String result = "";
        if (end != -1) {
            result = source.substring(start, end);
        }
        return result;
    }

    /**
     * 解析icon
     *
     * @param source
     * @return
     */
    private String getIconPath(String source) {
        String iconPath = null;
        try {
            int start = source.lastIndexOf("icon=") + 6;
            int end = source.lastIndexOf("'");
            iconPath = source.substring(start, end).trim().toLowerCase();
        } catch (Exception e) {
        }
        return iconPath;
    }

    /**
     * 解析package,versionCode,versionName
     *
     * @param apkDto
     * @param packageSource
     */
    private void splitPackageInfo(ApkDTO apkDto, String packageSource) {
        String[] packageInfo = packageSource.split(SPLIT_REGEX);
        apkDto.setPackageName(packageInfo[2]);
        apkDto.setVersionCode(packageInfo[4]);
        apkDto.setVersionName(packageInfo[6]);
    }


    /**
     * 获取文件大小
     *
     * @param path
     * @return
     */
    private long getSize(String path) {
        File file = new File(path);
        long size = 0;
        if (file.exists()) {
            try (FileInputStream fis = new FileInputStream(file);) {
                size = fis.available();
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
            }
        } else {
            LOG.error("file is not exist.");
        }
        return size;
    }

    /**
     * 抽取
     *
     * @param apkPath
     * @param iconPath
     * @param outPath  返回从定义ICON名称
     */
    private static String parseIcon(String apkPath, String iconPath, String outPath) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        ZipInputStream zis = null;
        File apkFile = new File(apkPath);
        String iconName = null;
        try {
            iconName = iconPath.substring(iconPath.lastIndexOf("/") + 1);
            fis = new FileInputStream(apkFile);
            zis = new ZipInputStream(fis);
            ZipEntry zipEntry = null;
            boolean flag = false;
            while ((zipEntry = zis.getNextEntry()) != null) {
                String name = zipEntry.getName().toLowerCase();
                if (name.endsWith("/" + iconName) && name.equals(iconPath)) {
                    UUID uuid = UUID.randomUUID();
                    iconName = uuid.toString() + "." + FilenameUtils.getExtension(iconName);
                    fos = new FileOutputStream(new File(outPath + iconName));
                    byte[] buffer = new byte[1024];
                    int n = 0;
                    while ((n = zis.read(buffer, 0, buffer.length)) != -1) {
                        fos.write(buffer, 0, n);
                    }
                    flag = true;
                    break;
                }
            }
            fos = null;
            zis.closeEntry();
            zipEntry = null;
            if (flag) {
                LOG.info("icon success," + iconPath);
            } else {
                LOG.info("icon failed," + iconPath);
                iconName = null;
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            try {
                if (zis != null) {
                    zis.close();
                }
                if (fis != null) {
                    fis.close();
                }
            } catch (Exception e) {
            }
        }
        return iconName;
    }
}
